/**
 * Copyright (C) 2011 Vinicius Vielmo Cogo, Marcelo Pasin, and the authors
 * indicated in the @author tags.
 * 
 * This file is part of DiversityAgent.
 * 
 * DiversityAgent is a free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * DiversityAgent is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with DiversityAgent. If not, see <http://www.gnu.org/licenses/>.
 */
package diversity_agent;

import java.io.Serializable;
import java.util.ArrayList;

/**
 * This class is responsible to maintain and provide all information stored on
 * DiversityAgent regarding the resources used by the service.
 * 
 * @author Vinicius Vielmo Cogo (vielmo at lasige.di.fc.ul.pt)
 * @version 0.1-beta
 * @since 2011-11-18
 * 
 */
public class DataContainer implements Serializable
{
	private static final long			serialVersionUID	= -2412921084042994705L;
	private ArrayList<Cloud>			mClouds;
	private ArrayList<Diversity>		mDiversities;
	private ArrayList<Image>			mImages;
	private ArrayList<VirtualMachine>	mVirtualMachines;
	private int							mNextVmId;

	// DataContainer initialisation ////////////////////////////////////////////
	/**
	 * 
	 */
	public DataContainer()
	{
		init();
	}

	/**
	 * 
	 */
	private void init()
	{
		this.mClouds = new ArrayList<Cloud>();
		this.mDiversities = new ArrayList<Diversity>();
		this.mImages = new ArrayList<Image>();
		this.mVirtualMachines = new ArrayList<VirtualMachine>();
		this.mNextVmId = -1;
	}

	// Diversity //////////////////////////////////////////////////////////////
	/**
	 * 
	 * @param theDiversity
	 * @return
	 */
	public boolean createDiversity(Diversity theDiversity)
	{
		if (mDiversities.contains(theDiversity)) {
			return false;
		} else {
			return mDiversities.add(theDiversity);
		}
	}

	/**
	 * Retrieve all diversities registered in this session
	 * 
	 * @return The list of registered diversities
	 */
	public ArrayList<Diversity> retrieveDiversities()
	{
		return this.mDiversities;
	}

	/**
	 * 
	 * @param theDiversity
	 * @return
	 */
	public boolean deleteDiversity(Diversity theDiversity)
	{
		return mDiversities.remove(theDiversity);
	}

	// Cloud //////////////////////////////////////////////////////////////////
	/**
	 * 
	 * @param theCloud
	 * @return
	 */
	public boolean createCloud(Cloud theCloud)
	{
		if (theCloud != null) {
			return mClouds.add(theCloud);
		} else {
			return false;
		}
	}

	/**
	 * Retrieve all clouds registered in this session
	 * 
	 * @return The list of registered clouds
	 */
	public ArrayList<Cloud> retrieveClouds()
	{
		return this.mClouds;
	}

	/**
	 * 
	 * @return
	 */
	public Cloud retrieveAnyCloud()
	{
		Cloud aCloud = null;
		if (mClouds.size() > 0) {
			aCloud = mClouds.get(Math.round((float) Math.random()
					* (mClouds.size() - 1)));
		}
		return aCloud;
	}

	/**
	 * 
	 * @param theCloudName
	 * @return
	 */
	public Cloud retrieveCloud(String theCloudName)
	{
		for (Cloud aCloud : mClouds) {
			if (theCloudName.equals(aCloud.getCloudName())) {
				return aCloud;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param theCloud
	 * @return
	 */
	public boolean deleteCloud(Cloud theCloud)
	{
		if (theCloud != null) {
			return mClouds.remove(theCloud);
		} else {
			return false;
		}
	}

	/**
	 * 
	 * @param theCloudName
	 * @return
	 */
	public boolean containsCloud(String theCloudName)
	{
		for (Cloud aCloud : mClouds) {
			if (theCloudName.equals(aCloud.getCloudName())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 * @param theCloudName
	 */
	public void blockCloud(String theCloudName)
	{
		for (int i = 0 ; i < mClouds.size() ; i++) {
			if (theCloudName.equals(mClouds.get(i).getCloudName())) {
				mClouds.get(i).block();
			}
		}
	}

	/**
	 * 
	 * @param theCloudName
	 */
	public void unblockCloud(String theCloudName)
	{
		for (int i = 0 ; i < mClouds.size() ; i++) {
			if (theCloudName.equals(mClouds.get(i).getCloudName())) {
				mClouds.get(i).unblock();
			}
		}
	}

	// Image //////////////////////////////////////////////////////////////////
	/**
	 * 
	 * @param theImage
	 * @return
	 */
	public boolean createImage(Image theImage)
	{
		if (theImage != null) {
			mImages.add(theImage);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Retrieve all VM images registered in this session
	 * 
	 * @return The list of registered images
	 */
	public ArrayList<Image> retrieveImages()
	{
		return this.mImages;
	}

	/**
	 * 
	 * @return
	 */
	public Image retrieveAnyImage()
	{
		Image aImage = null;
		if (mImages.size() > 0) {
			aImage = mImages.get(Math.round((float) Math.random()
					* (mImages.size() - 1)));
		}
		return aImage;
	}

	/**
	 * 
	 * @param theCloudName
	 * @return
	 */
	public Image retrieveAnyImage(String theCloudName)
	{
		for (Image aImage : mImages) {
			if (aImage.getAllocatedClouds().contains(theCloudName)) {
				return aImage;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param theImageName
	 * @return
	 */
	public Image retrieveImage(String theImageName)
	{
		for (Image aImage : mImages) {
			if (theImageName.equals(aImage.getName())) {
				return aImage;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param theImageName
	 * @return
	 */
	public boolean deleteImage(String theImageName)
	{
		return mImages.remove(theImageName);
	}

	// VirtualMachine /////////////////////////////////////////////////////////
	/**
	 * 
	 * @param theVirtualMachine
	 * @return
	 */
	public boolean createVm(VirtualMachine theVirtualMachine)
	{
		if (theVirtualMachine != null) {
			return mVirtualMachines.add(theVirtualMachine);
		} else {
			return false;
		}
	}

	/**
	 * Retrieve all virtual machines running in this session
	 * 
	 * @return The list of VMs running
	 */
	public ArrayList<VirtualMachine> retrieveVms()
	{
		return this.mVirtualMachines;
	}

	/**
	 * 
	 * @param theVmIdOnAgent
	 * @return
	 */
	public VirtualMachine retrieveVm(int theVmIdOnAgent)
	{
		for (VirtualMachine aVm : mVirtualMachines) {
			if (theVmIdOnAgent == aVm.getIdOnAgent()) {
				return aVm;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param theVm
	 * @return
	 */
	public boolean deleteVm(VirtualMachine theVm)
	{
		if (theVm != null) {
			return mVirtualMachines.remove(theVm);
		} else {
			return false;
		}
	}

	// Identifiers on agent ///////////////////////////////////////////////////
	/**
	 * 
	 * @return
	 */
	public Integer getNextVmId()
	{
		if (this.mNextVmId < Integer.MAX_VALUE) {
			return ++this.mNextVmId;
		} else {
			return -1;
		}
	}
}
